package com.ai.service.made.impl;


import com.ai.common.constant.AlgorithmConstant;
import com.ai.common.constant.CommonArgs;
import com.ai.common.CommonResponse;
import com.ai.common.constant.FunctionTypeConstants;
import com.ai.common.constant.PlcConstants;
import com.ai.entity.alarm.*;


import com.ai.entity.made.camera.CameraPO;
import com.ai.entity.network.IdentifySysToL1Message;
import com.ai.entity.server.ServerPO;
import com.ai.mapper.alarm.RecordAlarmMapper;
import com.ai.networking.netty.client.BootNettyClientChannelCache;
import com.ai.networking.websocket.service.WebSocket;
import com.ai.networking.websocket.service.entity.WSMessage;
import com.ai.service.made.*;
import com.ai.util.Base64Util;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mchange.v1.util.StringTokenizerUtils;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

import static com.ai.networking.netty.client.BootNettyClientChannelCache.clientSendMessage;

/**
 * <p>
 * 服务实现类
 *
 * </p>
 *
 * @author Mr.Chen
 * @since 2020-06-19
 */
@Service
@Slf4j
public class RecordAlarmServiceImpl extends ServiceImpl<RecordAlarmMapper, RecordAlarmPO> implements RecordAlarmService {

    @Resource
    RecordAlarmMapper recordAlarmMapper;
    @Resource
    CameraService cameraService;
    @Resource
    FunctionService functionService;

    @Resource
    L2SignalService l2SignalService;

    @Autowired
    private ServerService serverService;


    @Autowired
    private ISignalRecordService iSignalRecordService;

    private static volatile AtomicInteger FREQUENCY_A3_NUM= new AtomicInteger(0);


    /**
     * 算法提交识别警告
     *
     * @param alarmBOList
     * @return
     */
    @Override
    @Transactional
    public CommonResponse addAlarm(List<AlgorithmAlarmBO> alarmBOList) {
        log.info("===========================  # RecordAlarmServiceImpl.addAlarm #  ===========================");
        for (AlgorithmAlarmBO algorithmAlarmBO : alarmBOList) {
            String plcCode ="";

            if (algorithmAlarmBO.getCameraId() == null || algorithmAlarmBO.getCameraId() == 0) {
                return CommonResponse.error("没有摄像头ID");
            }
            if (StringUtils.isEmpty(algorithmAlarmBO.getSnapPhoto())) {
                return CommonResponse.error("没有抓拍图片");
            }

            if (StringUtils.isEmpty(algorithmAlarmBO.getFunctionType()) ) {
                return CommonResponse.error("没有警报类型");
            }

            CameraPO cameraPO = cameraService.getById(algorithmAlarmBO.getCameraId());

            if (cameraPO == null) {
                return CommonResponse.error("摄像头不存在");
            }


            SignalRecord signalRecord = iSignalRecordService.getById(algorithmAlarmBO.getTaskId());

            if (null == signalRecord ){
                return  CommonResponse.error("信号记录不存在");
            }else if ( !signalRecord.getFunStatus().equals("2")){
                log.info("===========================  当前操作信号已关闭：{}  ===========================",signalRecord.getFunType());
            }
            if (signalRecord.getSignalResource().equals(PlcConstants.PLC_1_IP)){
                plcCode= PlcConstants.PLC_1_CODE;
            } else if (signalRecord.getSignalResource().equals(PlcConstants.PLC_2_IP)) {
                plcCode=PlcConstants.PLC_2_CODE;
            }else if (signalRecord.getSignalResource().equals(PlcConstants.PLC_3_IP)) {
                plcCode=PlcConstants.PLC_3_CODE;
            }else if (signalRecord.getSignalResource().equals("192.168.8.33")) {
                // TODO: 2023-07-13 测试ip
                plcCode=PlcConstants.PLC_1_CODE;
            } else if (signalRecord.getSignalResource().equals("127.0.0.1")) {
                // TODO: 2023-07-13 测试ip
                plcCode=PlcConstants.PLC_1_CODE;
            }

            if (algorithmAlarmBO.getDoorNum() == null){
                algorithmAlarmBO.setDoorNum(signalRecord.getDoorNum());
            }

            SimpleDateFormat sformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = new Date();
            try {
                if (!StringUtils.isEmpty(algorithmAlarmBO.getCreateTime())) {
                    date = sformat.parse(algorithmAlarmBO.getCreateTime());
                }
            } catch (ParseException e) {
            }

            String webPhotoPath = "";
            String originalPath = "";
            String webVideoPath = algorithmAlarmBO.getSnapVideo();



            //处理渲染图图片
            if (!algorithmAlarmBO.getSnapPhoto().isEmpty()) {
                //base64，转存到本地，然后传入路径
                if (algorithmAlarmBO.getSnapPhotoStatus() == 2) {
                  String snapPhoto = Base64Util.GenerateFile("/images/",algorithmAlarmBO.getSnapPhoto(),
                          "jpg",cameraPO.getCode(),Integer.parseInt(algorithmAlarmBO.getFunctionType()),algorithmAlarmBO.getResult() );
                    webPhotoPath=snapPhoto;
                }else {
                    webPhotoPath=algorithmAlarmBO.getSnapPhoto();
                }

//                String photo = algorithmAlarmBO.getSnapPhoto();
//                if (photo.indexOf("http://") != -1) {
//                    webPhotoPath = photo;
//                } else {
//                    webPhotoPath = Base64Util.GenerateFile("/images/", photo, "jpg", cameraPO.getCode(), algorithmAlarmBO.getType(), algorithmAlarmBO.getState());
//                }
            }

            //处理原图
            if (org.apache.commons.lang3.StringUtils.isNotBlank(algorithmAlarmBO.getOriginalPhoto())){
                if (algorithmAlarmBO.getOriginalStatus() == 2) {
                    originalPath= Base64Util.GenerateFile("/original/",algorithmAlarmBO.getOriginalPhoto(),
                            "jpg",cameraPO.getCode(),Integer.parseInt(algorithmAlarmBO.getFunctionType()),algorithmAlarmBO.getResult() );
                }else {
                    originalPath=algorithmAlarmBO.getOriginalPhoto();
                }
                log.info("===========================  原图路径：{}  ===========================",originalPath);

            }

            //处理识别视频,先默认为路径
//            if (algorithmAlarmBO.getSnapVideoStatus() != null && algorithmAlarmBO.getSnapVideoStatus() != 0 && algorithmAlarmBO.getSnapVideoStatus() .equals(2) ) {
//
//                if (!StringUtils.isEmpty(algorithmAlarmBO.getSnapVideo())) {
//                    String snapVideo = Base64Util.GenerateFile("/videos/",algorithmAlarmBO.getSnapVideo(), "snapVideo/", "jpg");
//                    algorithmAlarmBO.setSnapVideo(snapVideo);
//                }
//            }

            int status = algorithmAlarmBO.getResult();
            Integer type = Integer.parseInt(algorithmAlarmBO.getFunctionType());

            //保存违规对象
            RecordAlarmPO alarmPO = new RecordAlarmPO();
            //视频路径
            alarmPO.setSnapVideo(algorithmAlarmBO.getSnapVideo());
            alarmPO.setCameraId(algorithmAlarmBO.getCameraId());
            alarmPO.setFunctionType(type);
            alarmPO.setSnapPhoto(webPhotoPath);
            alarmPO.setOriginalPhoto(originalPath);
            alarmPO.setSnapVideo(webVideoPath);
            alarmPO.setSubgroup(type);
            alarmPO.setCreateTime(date);
            alarmPO.setUpdateTime(date);
            alarmPO.setIsState(status);
            //开启算法时传过去的带钢号
            alarmPO.setStripNo(algorithmAlarmBO.getStripNo());
            //电文记录id
            alarmPO.setLogId(algorithmAlarmBO.getTaskId());

            // : 2023-07-10    以下字段算法识别结果未传递.
            alarmPO.setDetectionSprayNo(algorithmAlarmBO.getDetectionSprayNo());
            alarmPO.setOffset(algorithmAlarmBO.getOffset());
            alarmPO.setDetectionTimes(algorithmAlarmBO.getDetectionTimes());
            alarmPO.setStripWidth(algorithmAlarmBO.getStripWidth());
            alarmPO.setIsValid(algorithmAlarmBO.getIsValid());
            alarmPO.setDuration(algorithmAlarmBO.getDuration());

            save(alarmPO);


            if (type.equals(FunctionTypeConstants.A3_TRANSFER_SLAB_DEVIATION) ){
                // : 2023-07-12 如何确保是第二次收到收到的结果是同一次
                //A3移载机,两条记录同时为正常时才会通知前段拉取数据
                FREQUENCY_A3_NUM.incrementAndGet();
                if (FREQUENCY_A3_NUM.get() % 2 == 0 || status == 2){
                    //重置计数
                    FREQUENCY_A3_NUM.set(0);
                    /**
                     * 接收到两条A3移载机 的识别记录，或者 一条识别记录为异常的结果
                     * 关闭信号
                     */
                    signalRecord.setFunStatus("2");
                    iSignalRecordService.updateById(signalRecord);

                    sendWebSocket(type);
                    String finalPlcCode = plcCode;
                    new Thread(() -> sendMsgToPlc(signalRecord,algorithmAlarmBO, finalPlcCode)).start();

                }else {

                }

            }else {
                /**
                 * 将信号状态修改为关闭
                 */
                signalRecord.setFunStatus("2");
                iSignalRecordService.updateById(signalRecord);
                //通知界面拉取数据
                sendWebSocket(type);
                //通知plc
                String finalPlcCode1 = plcCode;
                new Thread(() -> sendMsgToPlc(signalRecord,algorithmAlarmBO, finalPlcCode1)).start();

            }


            algorithmAlarmBO.setSnapPhoto(webPhotoPath);
            algorithmAlarmBO.setSnapVideo(webVideoPath);
            algorithmAlarmBO.setState(status);

        }


        return CommonResponse.ok("警告发送成功");
    }

    /**
     * 向plc发送消息
     * @param signalRecord
     * @param algorithmAlarmBO
     */
    private void sendMsgToPlc(SignalRecord signalRecord, AlgorithmAlarmBO algorithmAlarmBO,String plcCode) {

        log.info("=========================== ## RecordAlarmServiceImpl.sendMsgToPlc ##  ===========================");
        log.info("===========================  接收到告警信息，准备向{},发送报文  ===========================",plcCode);
        String nettyCode = signalRecord.getNettyCode();
        Integer telID = getTelIDByFunType(Integer.parseInt(algorithmAlarmBO.getFunctionType()), signalRecord.getSignalResource());

        IdentifySysToL1Message identifySysToL1Message = new IdentifySysToL1Message();
        //电文号
        identifySysToL1Message.setTelID(telID);
        //版批号
        identifySysToL1Message.setPlanNo(algorithmAlarmBO.getStripNo());
        //炉门编号
        identifySysToL1Message.setDoorNum(algorithmAlarmBO.getDoorNum());
        // 1 正常 2 异常
        identifySysToL1Message.setResult(algorithmAlarmBO.getResult());
        String msgJSON = JSONObject.toJSONString(identifySysToL1Message);

        log.info("=========================== 开始组建报文：{}  ===========================",msgJSON);

        byte[] message;
        if (plcCode.equals(PlcConstants.PLC_1_CODE)){
            message = BootNettyClientChannelCache.createMessageToPlc1(identifySysToL1Message);
        }else {
            message = BootNettyClientChannelCache.createMessageToPlcOther(identifySysToL1Message);
        }
        try {
            log.info("===========================  准备获取channel发送信息  ===========================");
            Channel channel = BootNettyClientChannelCache.channelMapCache.get(plcCode).getChannel();
            log.info("===========================  channel获取完毕准备发送信息  ===========================");
            channel.writeAndFlush(Unpooled.copiedBuffer(message));
            channel.flush();
        }catch (Exception e){
            log.error("获取channel出现异常："+e);
        }

        log.info("向 {} 发送报文： 内容：{}",plcCode,message);
//        clientSendMessage(plcCode,identifySysToL1Message);

    }

    public static Integer getTelIDByFunType(Integer funType ,String clientIp){

        Integer telID = 0;

        if (funType.equals(FunctionTypeConstants.A3_TRANSFER_SLAB_DEVIATION)){
            telID= AlgorithmConstant.A3_TRANSFER_MACHINE_AUTOMATIC_CONFIRMATION;
        } else if (funType.equals(FunctionTypeConstants.SUPERPOSE_STEEL_IDENTIFICATION)) {
            //一个信号开启了两个功能，  那么收到某一个功能的信号识别记录是否需要通知plc
            telID=AlgorithmConstant.TRACK_STACKING_STEEL;

        } else if (funType.equals(FunctionTypeConstants.RANGING_STEEL)) {
            telID=AlgorithmConstant.TRACK_STACKING_STEEL;

        } else if (funType.equals(FunctionTypeConstants.LOAD_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_2_IP)) {
            telID=AlgorithmConstant.STEEL_INSTALLATION_DEVIATION_30_4;

        } else if (funType.equals(FunctionTypeConstants.TAKE_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_2_IP)) {
            telID=AlgorithmConstant.STEEL_DRAWING_DEVIATION_30_4;

        } else if (funType.equals(FunctionTypeConstants.STOVE_STATUS) && clientIp.equals(PlcConstants.PLC_2_IP)) {
            telID=AlgorithmConstant.FURNACE_DOOR_STATUS_30_4;

        }else if (funType.equals(FunctionTypeConstants.LOAD_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_3_IP)) {
            telID=AlgorithmConstant.STEEL_INSTALLATION_DEVIATION_30_5;

        } else if (funType.equals(FunctionTypeConstants.TAKE_STEEL_DEVIATION) && clientIp.equals(PlcConstants.PLC_3_IP)) {
            telID=AlgorithmConstant.STEEL_DRAWING_DEVIATION_30_5;

        } else if (funType.equals(FunctionTypeConstants.STOVE_STATUS) && clientIp.equals(PlcConstants.PLC_3_IP)) {
            telID=AlgorithmConstant.FURNACE_DOOR_STATUS_30_5;

        }
        return telID;
    }


    private void sendWebSocket(int type) {
        WSMessage wsMessage = new WSMessage();
        wsMessage.setContent("UPDATE");

        if (CommonArgs.WS_RECORD_MAP.containsKey(type)
                && CommonArgs.WS_RECORD_MAP.get(type) != null
                && CommonArgs.WS_RECORD_MAP.get(type).size() > 0) {
            CopyOnWriteArraySet<WebSocket> webSockets = CommonArgs.WS_RECORD_MAP.get(type);
            for (WebSocket ws : webSockets) {
                ws.sendMessage(wsMessage);
            }
        }
    }

    private void sendHttp(RecordAlarmPO alarmPO) {


    }


    /**
     * 分页查询
     *
     * @param page
     * @return
     */
    @Override
    public CommonResponse selectByPage(RecordAlarmPage page) {
        QueryWrapper<RecordAlarmPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("create_time");
        queryWrapper = page.getQuery(queryWrapper);
        IPage<RecordAlarmVO> voIPage = recordAlarmMapper.getRecordListQuickly(page, queryWrapper);
        List<RecordAlarmVO> records = voIPage.getRecords();


        for (RecordAlarmVO record : records) {
            String name = functionService.getNameByCode(record.getFunctionType());
            CameraPO cameraPO = cameraService.getById(record.getCameraId());
            record.setFunctionNickname(name);
            record.setCameraNickname(cameraPO == null ? "" : cameraPO.getNickname());
        }
        voIPage.setRecords(records);
        return CommonResponse.ok(voIPage);
    }

    /**
     * 是否误报
     *
     * @param recordAlarmBO
     * @return
     */
    @Override
    public CommonResponse signError(RecordAlarmBO recordAlarmBO) {
        RecordAlarmBO alarmBO = new RecordAlarmBO();
        alarmBO.setId(recordAlarmBO.getId());
        alarmBO.setIsError(recordAlarmBO.getIsError());
        RecordAlarmPO recordAlarmPO = alarmBO.convertBOToPO(alarmBO);
        if (updateById(recordAlarmPO)) {
            return CommonResponse.ok("标记成功");
        }
        return CommonResponse.error("标记失败");
    }
}
